<?php

namespace ali\easysdk\fund\trans;

use ali\easysdk\fund\trans\Models\AlipayFundTransUniTransferResponse;
use AlibabaCloud\Tea\Exception\TeaError;
use AlibabaCloud\Tea\Exception\TeaUnableRetryError;
use AlibabaCloud\Tea\Request;
use AlibabaCloud\Tea\Tea;
use Alipay\EasySDK\Kernel\EasySDKKernel;
use Alipay\EasySDK\Payment\Common\Models\AlipayTradeCreateResponse;

class Client
{
    /**
     * @var EasySDKKernel
     */
    protected $_kernel;

    public function __construct($kernel){
        $this->_kernel = $kernel;
    }

    /**
     * 单笔转账接口
     * @param $outBizNo     商家侧唯一订单号，由商家自定义。对于不同转账请求，商家需保证该订单号在自身系统唯一。
     * @param $transAmount  订单总金额，单位为元，不支持千位分隔符，精确到小数点后两位，取值范围[0.1,100000000]。
     * @param $productCode  销售产品码。单笔无密转账固定为 TRANS_ACCOUNT_NO_PWD。
     * @param $bizScene     业务场景。单笔无密转账固定为 DIRECT_TRANSFER。
     * @param $orderTitle   转账业务的标题，用于在支付宝用户的账单里显示。
     * @param $businessParams   转账业务请求的扩展参数，支持传入的扩展参数如下：payer_show_name_use_alias：是否展示付款方别名，可选，收款方在支付宝账单中可见。枚举支持： true：展示别名，将展示商家支付宝在商家中心 商户信息 > 商户基本信息 页面配置的 商户别名。 false：不展示别名。默认为 false。
     * @param $identity     参与方的标识 ID。当 identity_type=ALIPAY_USER_ID 时，填写支付宝用户 UID。示例值：2088123412341234。当 identity_type=ALIPAY_LOGON_ID 时，填写支付宝登录号。示例值：186xxxxxxxx。
     * @param $identityType 参与方的标识类型，目前支持如下枚举： ALIPAY_USER_ID：支付宝会员的用户 ID，可通过 获取会员信息 能力获取。 ALIPAY_LOGON_ID：支付宝登录号，支持邮箱和手机号格式。
     * @return AlipayFundTransUniTransferResponse
     */
    public function uniTransfer($outBizNo, $transAmount, $productCode, $bizScene, $orderTitle, $businessParams, $identity, $identityType){
        $_runtime = [
            "ignoreSSL" => $this->_kernel->getConfig("ignoreSSL"),
            "httpProxy" => $this->_kernel->getConfig("httpProxy"),
            "connectTimeout" => 15000,
            "readTimeout" => 15000,
            "retry" => [
                "maxAttempts" => 0
            ]
        ];
        $_lastRequest = null;
        $_lastException = null;
        $_now = time();
        $_retryTimes = 0;
        while (Tea::allowRetry(@$_runtime["retry"], $_retryTimes, $_now)) {
            if ($_retryTimes > 0) {
                $_backoffTime = Tea::getBackoffTime(@$_runtime["backoff"], $_retryTimes);
                if ($_backoffTime > 0) {
                    Tea::sleep($_backoffTime);
                }
            }
            $_retryTimes = $_retryTimes + 1;
            try {
                $_request = new Request();
                $systemParams = [
                    "method" => "alipay.fund.trans.uni.transfer",
                    "app_id" => $this->_kernel->getConfig("appId"),
                    "timestamp" => $this->_kernel->getTimestamp(),
                    "format" => "json",
                    "version" => "1.0",
                    "alipay_sdk" => $this->_kernel->getSdkVersion(),
                    "charset" => "UTF-8",
                    "sign_type" => $this->_kernel->getConfig("signType"),
                    "app_cert_sn" => $this->_kernel->getMerchantCertSN(),
                    "alipay_root_cert_sn" => $this->_kernel->getAlipayRootCertSN()
                ];

                $bizParams = [
                    "out_biz_no" => $outBizNo,
                    "trans_amount" => $transAmount,
                    "product_code" => $productCode,
                    "biz_scene" => $bizScene,
                    "order_title" => $orderTitle,
                    "business_params" => $businessParams,
                    'payee_info'    => [
                        'identity'  => $identity,
                        'identity_type' => $identityType,
                    ],
                ];

                $textParams = [];
                $_request->protocol = $this->_kernel->getConfig("protocol");
                $_request->method = "POST";
                $_request->pathname = "/gateway.do";
                $_request->headers = [
                    "host" => $this->_kernel->getConfig("gatewayHost"),
                    "content-type" => "application/x-www-form-urlencoded;charset=utf-8"
                ];
                $_request->query = $this->_kernel->sortMap(Tea::merge([
                    "sign" => $this->_kernel->sign($systemParams, $bizParams, $textParams, $this->_kernel->getConfig("merchantPrivateKey"))
                ], $systemParams, $textParams));
                $_request->body = $this->_kernel->toUrlEncodedRequestBody($bizParams);
                $_lastRequest = $_request;
                $_response= Tea::send($_request, $_runtime);
                $respMap = $this->_kernel->readAsJson($_response, "alipay.fund.trans.uni.transfer");
                if ($this->_kernel->isCertMode()) {
                    if ($this->_kernel->verify($respMap, $this->_kernel->extractAlipayPublicKey($this->_kernel->getAlipayCertSN($respMap)))) {
                        return AlipayFundTransUniTransferResponse::fromMap($this->_kernel->toRespModel($respMap));
                    }
                }
                else {
                    if ($this->_kernel->verify($respMap, $this->_kernel->getConfig("alipayPublicKey"))) {
                        return AlipayFundTransUniTransferResponse::fromMap($this->_kernel->toRespModel($respMap));
                    }
                }
                throw new TeaError([
                    "message" => "验签失败，请检查支付宝公钥设置是否正确。"
                ]);
            }
            catch (\Exception $e) {
                if (!($e instanceof TeaError)) {
                    $e = new TeaError([], $e->getMessage(), $e->getCode(), $e);
                }
                if (Tea::isRetryable($e)) {
                    $_lastException = $e;
                    continue;
                }
                throw $e;
            }
        }
        throw new TeaUnableRetryError($_lastRequest, $_lastException);
    }

    /**
     * 设置API入参中没有的其他可选业务请求参数(biz_content下的字段)
     *
     * @param $key   String 业务请求参数名称（biz_content下的字段名，比如timeout_express）
     * @param $value object 业务请求参数的值，一个可以序列化成JSON的对象
     *               如果该字段是一个字符串类型（String、Price、Date在SDK中都是字符串），请使用String储存
     *               如果该字段是一个数值型类型（比如：Number），请使用Long储存
     *               如果该字段是一个复杂类型，请使用嵌套的array指定各下级字段的值
     *               如果该字段是一个数组，请使用array储存各个值
     * @return $this
     */
    public function optional($key, $value)
    {
        $this->_kernel->injectBizParam($key, $value);
        return $this;
    }

    /**
     * 批量设置API入参中没有的其他可选业务请求参数(biz_content下的字段)
     * optional方法的批量版本
     *
     * @param $optionalArgs array 可选参数集合，每个参数由key和value组成，key和value的格式请参见optional方法的注释
     * @return $this
     */
    public function batchOptional($optionalArgs)
    {
        foreach ($optionalArgs as $key => $value) {
            $this->_kernel->injectBizParam($key, $value);
        }
        return $this;
    }
}